iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0

Upload file 是一個比較特別的 Component,如果我們想直接利用既有的 rerun 功能來傳送檔案資料,就必須先將檔案轉換成 base64 編碼,再將整個編碼後的資料一併傳給伺服器。然而,這種做法會帶來兩個問題:

  • 傳輸量增加: 將檔案轉換成 base64 後,資料量會變得更大,增加了網路傳輸的負擔。
  • 效能降低: 在前端進行 base64 轉換會消耗更多的計算資源,影響用戶體驗。

為了避免上述問題,我們為檔案上傳新增一個 endpoint 。前端在選擇檔案後,直接將檔案透過這個 endpoint 傳送到伺服器。伺服器處理完檔案後,再觸發 rerun 操作。

前端:

async function uploadFile(compID, file) {
    // ...
    const formData = new FormData()
    formData.append('file', file, file.name)
    // ...
}

function createUploadFile(comp) {
    // DOM

    inputEle.onchange = (e) => {
        e.preventDefault();
 
        if (!e.target.files) {
            return
        }
 
        const file = e.target.files[0]
 
        uploadFile(e.target.id, file).then(async resp => {
            if (resp.status != 200) {
                console.error(resp)
                return
            }
 
            const fileResp = await resp.json()
 
            state[e.target.id] = fileResp
            rerun({})
        })
    }

}

後端:

http.HandleFunc("POST /api/files", func(w http.ResponseWriter, r *http.Request) {
    // ...
    err := r.ParseMultipartForm(MaxUploadSize)
    // ...
    file, handler, err := r.FormFile("file")
    // ...
    
    // 這裡我直接把檔案塞給記憶體了,但理論上需要開選項給開發者選擇記憶體或暫存檔案。
    bs, err := io.ReadAll(file)
    //...
 
    stateFile := &tgstate.File{
        Name:  handler.Filename,
        Size:  handler.Size,
        Type:  http.DetectContentType(bs),
        Bytes: bs,
    }
 
    state.Set(compID, stateFile)
    
    // ...
})

目前的實作有幾個問題:

  • 檔案大小: 目前程式碼直接將檔案讀入記憶體,對於大檔案可能導致記憶體不足。可能需要將檔案存儲到伺服器磁碟上,並記錄檔案路徑。
  • 錯誤處理: 完善錯誤處理機制,例如檔案上傳失敗、伺服器錯誤等。

這些坑先暫時記著好了,之後再回來填。


上一篇
Day12 Image Component
下一篇
Day14 Component 實作告一段落
系列文
用 Golang 實作 streamlit 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言